"""
Simplified GSM CLI focused on XML configuration management.
Now that the solver reads XML directly, GSM becomes a configuration manager.
"""

import click
from rich.console import Console
from rich.table import Table
from rich.syntax import Syntax
from pathlib import Path
from typing import Dict, Any
import sys
import os

console = Console()

# Import our components
try:
    from ..config.xml_config import XMLConfigParser
    from ..test.xml_runner import XMLTestRunner
except ImportError:
    console.print("[red]Error: GSM components not found. Please install gcr-solver-manager.[/red]")
    sys.exit(1)


@click.group()
@click.version_option()
def cli():
    """
    🚀 GCR Solver Manager - XML Configuration Edition
    
    Simplified interface for managing XML configurations and running solver tests.
    The heavy lifting is now done by the solver itself!
    """
    pass


# ==============================================================================
# PRIMARY COMMANDS - These are the main commands users should use
# ==============================================================================

@cli.command()
@click.argument('config_file', type=click.Path(exists=True))
@click.option('--override', '-o', multiple=True, 
              help='Override parameter: Section.param=value (e.g., Solver.max_iterations=50)')
@click.option('--validate-only', is_flag=True, help='Only validate configuration, do not run')
def run(config_file: str, override: tuple, validate_only: bool):
    """
    🚀 Run solver with XML configuration file.
    
    This is the main command for running solver tests.
    
    \b
    Examples:
        gsm run config/debug_cuda_gmres.xml
        gsm run config/base.xml -o Solver.max_iterations=50
        gsm run config/test.xml -o Problem.resolution=0.5 -o System.gpu_backend=hip
    """
    runner = XMLTestRunner()
    
    # Validate configuration first
    is_valid, errors = runner.validate_config(config_file)
    if not is_valid:
        console.print(f"❌ [red]Invalid configuration: {config_file}[/red]")
        for error in errors:
            console.print(f"  • {error}")
        sys.exit(1)
    
    if validate_only:
        console.print(f"✅ [green]Configuration is valid: {config_file}[/green]")
        return
    
    # Parse overrides
    overrides = {}
    for override_str in override:
        if '=' in override_str and '.' in override_str:
            key, value = override_str.split('=', 1)
            overrides[key] = value
        else:
            console.print(f"❌ [red]Invalid override format: {override_str}[/red]")
            console.print("Use format: Section.parameter=value")
            sys.exit(1)
    
    console.print(f"🚀 Running solver with: [cyan]{config_file}[/cyan]")
    if overrides:
        console.print(f"📝 Overrides: {overrides}")
    
    success, run_id = runner.run_with_xml_config(config_file, overrides=overrides)
    
    if success:
        console.print(f"✅ [green]Success![/green] (run_id: {run_id})")
    else:
        console.print(f"❌ [red]Failed[/red] (run_id: {run_id})")
        sys.exit(1)


@cli.command()
def list():
    """📋 List available XML configuration files."""
    runner = XMLTestRunner()
    configs = runner.list_available_configs()
    
    if not configs:
        console.print("❌ No XML configuration files found in config/ directory")
        console.print("💡 Create one with: [cyan]gsm create[/cyan]")
        return
    
    table = Table(title="📄 Available Configurations")
    table.add_column("File", style="cyan", no_wrap=True)
    table.add_column("Description", style="green")
    table.add_column("Solver", style="yellow")
    table.add_column("GPU", style="magenta")
    table.add_column("Processes", style="blue")
    
    for config in configs:
        try:
            info = _get_config_info(config)
            table.add_row(
                config,
                info['description'],
                info['solver'],
                info['gpu'],
                str(info['processes'])
            )
        except:
            table.add_row(config, "Error reading", "?", "?", "?")
    
    console.print(table)


@cli.command()
@click.option('--solver', type=click.Choice(['gcr', 'ca-gcr', 'gmres', 'bca-gmres']), 
              required=True, help='Solver type')
@click.option('--gpu', type=click.Choice(['cuda', 'hip', 'none']), 
              default='none', help='GPU backend')
@click.option('--debug/--no-debug', default=False, help='Enable debug mode')
@click.option('--nproc', type=int, default=4, help='Number of MPI processes')
@click.option('--resolution', type=float, default=1.0, 
              help='Problem resolution (0.25, 0.5, 1.0)')
@click.option('--maxit', type=int, default=20, help='Maximum iterations')
@click.argument('output_file', type=click.Path())
def create(solver: str, gpu: str, debug: bool, nproc: int, resolution: float, 
           maxit: int, output_file: str):
    """
    ⚙️ Create XML configuration file from parameters.
    
    \b
    Examples:
        gsm create --solver=gmres --gpu=cuda --debug config/my_test.xml
        gsm create --solver=ca-gcr --nproc=16 --resolution=0.25 config/production.xml
    """
    runner = XMLTestRunner()
    
    params = {
        'debug': debug,
        'nproc': nproc,
        'resolution': resolution,
        'maxit': maxit
    }
    
    # Create configuration
    try:
        config_path = runner.create_config_from_params(
            solver=solver,
            gpu=gpu,
            params=params,
            config_name=Path(output_file).name
        )
        
        # Move to desired location
        output_path = Path(output_file)
        output_path.parent.mkdir(parents=True, exist_ok=True)
        if config_path != output_path:
            config_path.rename(output_path)
            config_path = output_path
        
        console.print(f"✅ [green]Created: {config_path}[/green]")
        console.print(f"📝 {solver.upper()} solver, {gpu} GPU, {nproc} processes")
        console.print(f"🚀 Run with: [cyan]gsm run {config_path}[/cyan]")
        
    except Exception as e:
        console.print(f"❌ [red]Failed to create configuration: {e}[/red]")
        sys.exit(1)


@cli.command()
@click.argument('config_file', type=click.Path(exists=True))
def info(config_file: str):
    """ℹ️ Show detailed configuration information."""
    try:
        info = _get_config_info(config_file)
        
        console.print(f"📄 [bold]{config_file}[/bold]")
        console.print()
        
        # Create info table
        table = Table(show_header=False, box=None)
        table.add_column("Key", style="cyan", min_width=15)
        table.add_column("Value", style="green")
        
        table.add_row("Solver", info['solver'])
        table.add_row("GPU Backend", info['gpu'])
        table.add_row("Debug Mode", "Yes" if info['debug'] else "No")
        table.add_row("MPI Processes", str(info['processes']))
        table.add_row("Resolution", str(info['resolution']))
        table.add_row("Max Iterations", str(info['maxit']))
        table.add_row("Communication", info['communication'])
        
        console.print(table)
        console.print()
        console.print(f"🚀 Run with: [cyan]gsm run {config_file}[/cyan]")
        
    except Exception as e:
        console.print(f"❌ [red]Error reading configuration: {e}[/red]")


@cli.command()
@click.argument('config_file', type=click.Path(exists=True))
def show(config_file: str):
    """👀 Show XML configuration file contents."""
    try:
        with open(config_file, 'r') as f:
            xml_content = f.read()
        
        syntax = Syntax(xml_content, "xml", theme="monokai", line_numbers=True)
        console.print(f"📄 [bold]{config_file}[/bold]")
        console.print(syntax)
        
    except Exception as e:
        console.print(f"❌ [red]Error reading file: {e}[/red]")


@cli.command()
@click.argument('config_file', type=click.Path(exists=True))
def validate(config_file: str):
    """✅ Validate XML configuration file."""
    runner = XMLTestRunner()
    is_valid, errors = runner.validate_config(config_file)
    
    if is_valid:
        console.print(f"✅ [green]Valid configuration: {config_file}[/green]")
    else:
        console.print(f"❌ [red]Invalid configuration: {config_file}[/red]")
        for error in errors:
            console.print(f"  • {error}")
        sys.exit(1)


# ==============================================================================
# TEMPLATE COMMANDS - Quick configuration creation
# ==============================================================================

@cli.group()
def template():
    """📋 Create configurations from standard templates."""
    pass


@template.command()
@click.argument('output_file', type=click.Path())
def debug_cuda_gmres(output_file: str):
    """Create debug CUDA GMRES configuration (2 procs, 1 iteration)."""
    _create_template('debug-cuda-gmres', output_file)


@template.command()
@click.argument('output_file', type=click.Path())
def debug_hip_gcr(output_file: str):
    """Create debug HIP GCR configuration (2 procs, 1 iteration)."""
    _create_template('debug-hip-gcr', output_file)


@template.command()
@click.argument('output_file', type=click.Path())
def production_ca_gcr(output_file: str):
    """Create production CA-GCR configuration (16 procs, 0.25° resolution)."""
    _create_template('production-ca-gcr', output_file)


@template.command()
@click.argument('output_file', type=click.Path())
def benchmark(output_file: str):
    """Create benchmark configuration (8 procs, 0.5° resolution)."""
    _create_template('benchmark', output_file)


def _create_template(template_name: str, output_file: str):
    """Helper to create template configurations."""
    templates = {
        'debug-cuda-gmres': {
            'solver': 'gmres', 'gpu': 'cuda', 'debug': True, 
            'nproc': 2, 'maxit': 1, 'resolution': 1.0
        },
        'debug-hip-gcr': {
            'solver': 'gcr', 'gpu': 'hip', 'debug': True, 
            'nproc': 2, 'maxit': 1, 'resolution': 1.0
        },
        'production-ca-gcr': {
            'solver': 'ca-gcr', 'gpu': 'cuda', 'debug': False, 
            'nproc': 16, 'maxit': 100, 'resolution': 0.25
        },
        'benchmark': {
            'solver': 'gcr', 'gpu': 'cuda', 'debug': False, 
            'nproc': 8, 'maxit': 50, 'resolution': 0.5
        }
    }
    
    template_config = templates[template_name]
    runner = XMLTestRunner()
    
    try:
        config_path = runner.create_config_from_params(
            solver=template_config['solver'],
            gpu=template_config['gpu'],
            params=template_config,
            config_name=Path(output_file).name
        )
        
        # Move to desired location
        output_path = Path(output_file)
        output_path.parent.mkdir(parents=True, exist_ok=True)
        if config_path != output_path:
            config_path.rename(output_path)
        
        console.print(f"✅ [green]Created {template_name} template: {output_path}[/green]")
        console.print(f"🚀 Run with: [cyan]gsm run {output_path}[/cyan]")
        
    except Exception as e:
        console.print(f"❌ [red]Failed to create template: {e}[/red]")


# ==============================================================================
# GCR-JULIA INTEGRATION
# ==============================================================================

@cli.group()
def julia():
    """
    🔬 GCR-Julia solver integration.
    
    Run high-performance Julia-based GCR solvers with various backends.
    """
    pass


@julia.command()
@click.argument('problem_size', type=int)
@click.option('--algorithm', '-a', default='gcr', 
              type=click.Choice(['gcr', 'enhanced-gcr', 'ca-gcr', 'gmres', 'bca-gmres']),
              help='Solver algorithm')
@click.option('--backend', '-b', default='cpu',
              type=click.Choice(['cpu', 'gpu-cuda', 'gpu-amdgpu', 'petsc-mpi']),
              help='Computational backend')
@click.option('--tolerance', '-t', default=1e-6, type=float, help='Convergence tolerance')
@click.option('--max-iter', '-m', default=1000, type=int, help='Maximum iterations')
@click.option('--restart', '-r', default=50, type=int, help='Restart frequency')
@click.option('--verbose', '-v', is_flag=True, help='Enable verbose output')
@click.option('--save-results', '-s', is_flag=True, help='Save results to file')
@click.option('--julia-threads', default=0, type=int, help='Julia thread count (0=auto)')
def solve(problem_size, algorithm, backend, tolerance, max_iter, restart, verbose, save_results, julia_threads):
    """
    🚀 Solve a linear system using GCR-Julia.
    
    \b
    Examples:
        gsm julia solve 1000 --algorithm=gcr --backend=cpu
        gsm julia solve 10000 --algorithm=ca-gcr --backend=gpu-cuda --verbose
        gsm julia solve 5000 --algorithm=gmres --backend=petsc-mpi --tolerance=1e-8
    """
    import subprocess
    import time
    from pathlib import Path
    
    # Path to GCR-Julia package
    gcr_julia_path = Path(__file__).parent.parent.parent.parent.parent / "GCR-Julia"
    
    if not gcr_julia_path.exists():
        console.print(f"❌ [red]GCR-Julia package not found at {gcr_julia_path}[/red]")
        console.print("Please ensure GCR-Julia is available in the expected location.")
        sys.exit(1)
    
    console.print(f"🔬 [cyan]Running GCR-Julia solver[/cyan]")
    console.print(f"   📊 Problem size: {problem_size}")
    console.print(f"   🧮 Algorithm: {algorithm}")
    console.print(f"   ⚡ Backend: {backend}")
    console.print(f"   📏 Tolerance: {tolerance}")
    
    # Create Julia script
    julia_script = f"""
using LinearAlgebra, SparseArrays
using Random
Random.seed!(42)

# Change to GCR-Julia directory and activate project
cd("{gcr_julia_path}")
using Pkg
Pkg.activate(".")

# Load GCR package
using GCR

# Generate test problem
println("🔧 Generating {problem_size}×{problem_size} test matrix...")
n = {problem_size}
A = generate_test_matrix(Float64, n, type=:spd, condition_number=1e6)
b = randn(n)

# Configure solver
options = Dict(
    "tolerance" => {tolerance},
    "max_iterations" => {max_iter},
    "restart" => {restart},
    "verbose" => {'true' if verbose else 'false'},
    "backend" => "{backend}",
    "algorithm" => "{algorithm}"
)

println("🚀 Starting {algorithm} solver...")
start_time = time()

try
    # Select and run solver based on algorithm
    if options["algorithm"] == "gcr"
        result = solve_gcr(A, b, tol={tolerance}, maxiter={max_iter}, restart={restart}, verbose={'true' if verbose else 'false'})
    elseif options["algorithm"] == "enhanced-gcr"
        result = solve_enhanced_gcr(A, b, tol={tolerance}, maxiter={max_iter}, adaptive_restart=true, verbose={'true' if verbose else 'false'})
    elseif options["algorithm"] == "ca-gcr"
        result = solve_ca_gcr(A, b, s=4, tol={tolerance}, maxiter={max_iter}, verbose={'true' if verbose else 'false'})
    elseif options["algorithm"] == "gmres"
        result = solve_gmres(A, b, tol={tolerance}, maxiter={max_iter}, restart={restart}, verbose={'true' if verbose else 'false'})
    elseif options["algorithm"] == "bca-gmres"
        # For single RHS, create a matrix
        B = reshape(b, n, 1)
        result = solve_bca_gmres(A, B, tol={tolerance}, maxiter={max_iter}, verbose={'true' if verbose else 'false'})
        # Extract single solution
        if isdefined(result, :solution)
            result = GCRResult(result.converged, result.iterations, result.residual_norm, result.solve_time, result.info, result.solution[:, 1])
        end
    else
        error("Unsupported algorithm: " * options["algorithm"])
    end
    
    solve_time = time() - start_time
    
    # Display results
    println()
    println("✅ [bold green]Solver completed successfully![/bold green]")
    println("📊 Results:")
    
    if isdefined(result, :converged) && result.converged
        println("   ✓ Converged: Yes")
    else
        println("   ✗ Converged: No")
    end
    
    if isdefined(result, :iterations)
        println("   🔄 Iterations: ", result.iterations)
    end
    
    if isdefined(result, :residual_norm)
        println("   📏 Final residual: ", result.residual_norm)
    end
    
    println("   ⏱️  Solve time: ", round(solve_time, digits=3), " seconds")
    
    # Verify solution
    if isdefined(result, :solution)
        x = result.solution
        residual = norm(A * x - b)
        println("   ✅ Verification residual: ", residual)
        
        if residual < {tolerance} * 10
            println("   ✓ Solution verification: PASSED")
        else
            println("   ⚠️  Solution verification: WARNING (high residual)")
        end
    end
    
    # Save results if requested
    if {'true' if save_results else 'false'} == "true"
        import JSON
        results_file = "gcr_julia_results_$(now()).json"
        results_data = Dict(
            "problem_size" => n,
            "algorithm" => options["algorithm"],
            "backend" => options["backend"],
            "converged" => isdefined(result, :converged) ? result.converged : false,
            "iterations" => isdefined(result, :iterations) ? result.iterations : -1,
            "residual_norm" => isdefined(result, :residual_norm) ? result.residual_norm : NaN,
            "solve_time" => solve_time,
            "tolerance" => {tolerance}
        )
        
        open(results_file, "w") do f
            JSON.print(f, results_data, 2)
        end
        println("   💾 Results saved to: ", results_file)
    end
    
catch e
    println()
    println("❌ [bold red]Solver failed with error:[/bold red]")
    println("   Error: ", e)
    exit(1)
end
"""
    
    # Set Julia environment
    julia_env = dict(os.environ)
    if julia_threads > 0:
        julia_env['JULIA_NUM_THREADS'] = str(julia_threads)
    
    try:
        # Run Julia script
        console.print(f"⚡ Executing Julia solver...")
        result = subprocess.run(
            ["julia", "--project=" + str(gcr_julia_path), "-e", julia_script],
            env=julia_env,
            capture_output=False,
            text=True,
            timeout=300  # 5 minute timeout
        )
        
        if result.returncode == 0:
            console.print(f"🎉 [bold green]GCR-Julia execution completed![/bold green]")
        else:
            console.print(f"❌ [red]GCR-Julia execution failed with return code {result.returncode}[/red]")
            sys.exit(1)
            
    except subprocess.TimeoutExpired:
        console.print(f"❌ [red]GCR-Julia execution timed out after 5 minutes[/red]")
        sys.exit(1)
    except FileNotFoundError:
        console.print(f"❌ [red]Julia executable not found. Please install Julia ≥1.9[/red]")
        sys.exit(1)
    except Exception as e:
        console.print(f"❌ [red]GCR-Julia execution failed: {e}[/red]")
        sys.exit(1)


@julia.command()
def status():
    """
    ℹ️  Check GCR-Julia environment status.
    """
    import subprocess
    from pathlib import Path
    
    console.print("[bold cyan]🔬 GCR-Julia Environment Status[/bold cyan]\n")
    
    # Check Julia installation
    try:
        result = subprocess.run(["julia", "--version"], capture_output=True, text=True, timeout=10)
        if result.returncode == 0:
            version = result.stdout.strip()
            console.print(f"✅ Julia: {version}")
        else:
            console.print("❌ Julia: Not working properly")
    except FileNotFoundError:
        console.print("❌ Julia: Not found in PATH")
    except Exception as e:
        console.print(f"❌ Julia: Error ({e})")
    
    # Check GCR-Julia package
    gcr_julia_path = Path(__file__).parent.parent.parent.parent.parent / "GCR-Julia"
    if gcr_julia_path.exists():
        console.print(f"✅ GCR-Julia package: Found at {gcr_julia_path}")
        
        # Check if package can be loaded
        try:
            test_script = f"""
            cd("{gcr_julia_path}")
            using Pkg
            Pkg.activate(".")
            using GCR
            println("GCR.jl loaded successfully")
            """
            result = subprocess.run(
                ["julia", "-e", test_script],
                capture_output=True, text=True, timeout=30
            )
            if result.returncode == 0:
                console.print("✅ GCR-Julia loading: Working")
            else:
                console.print("❌ GCR-Julia loading: Failed")
                console.print(f"   Error: {result.stderr}")
        except Exception as e:
            console.print(f"❌ GCR-Julia loading: Error ({e})")
    else:
        console.print(f"❌ GCR-Julia package: Not found at {gcr_julia_path}")
    
    # Check GPU extensions
    console.print("\n[bold cyan]GPU Extensions:[/bold cyan]")
    try:
        gpu_script = """
        try; using CUDA; println("CUDA: ", CUDA.has_cuda()); catch; println("CUDA: false"); end
        try; using AMDGPU; println("AMDGPU: ", AMDGPU.has_rocm_gpu()); catch; println("AMDGPU: false"); end
        """
        result = subprocess.run(["julia", "-e", gpu_script], capture_output=True, text=True, timeout=15)
        if result.returncode == 0:
            for line in result.stdout.strip().split('\n'):
                if ': true' in line:
                    console.print(f"✅ {line}")
                else:
                    console.print(f"❌ {line}")
        else:
            console.print("❌ GPU extension check failed")
    except Exception as e:
        console.print(f"❌ GPU extension check error: {e}")


@julia.command()
@click.argument('config_file', type=click.Path(exists=True))
def run_config(config_file):
    """
    🔧 Run GCR-Julia solver with GSM XML configuration.
    
    Converts GSM XML configuration to GCR-Julia parameters and runs the solver.
    """
    from pathlib import Path
    
    # Parse GSM XML configuration
    try:
        parser = XMLConfigParser()
        if not parser.load_from_file(config_file):
            console.print(f"❌ [red]Cannot parse XML configuration: {config_file}[/red]")
            sys.exit(1)
        
        config = parser.parse()
        
        # Extract parameters
        system = config.get_sublist("System")
        solver = config.get_sublist("Solver") 
        problem = config.get_sublist("Problem")
        
        # Map to GCR-Julia parameters
        gpu_backend = system.get_string("gpu_backend", "none")
        if gpu_backend.lower() == "cuda":
            backend = "gpu-cuda"
        elif gpu_backend.lower() == "hip":
            backend = "gpu-amdgpu"  # Map HIP to AMDGPU
        else:
            backend = "cpu"
        
        algorithm = solver.get_string("type", "gcr").lower()
        if algorithm not in ['gcr', 'gmres', 'ca-gcr', 'bca-gmres']:
            # Map common variants
            if algorithm in ['cagcr', 'ca_gcr']:
                algorithm = 'ca-gcr'
            elif algorithm in ['bcagmres', 'bca_gmres']:
                algorithm = 'bca-gmres'
            else:
                algorithm = 'gcr'  # Default
        
        # Problem size (estimate from resolution)
        resolution = problem.get_double("resolution", 1.0)
        # Estimate grid size based on resolution (typical PDE discretization)
        grid_size = max(100, int(1.0 / resolution))
        problem_size = min(grid_size * grid_size, 50000)  # Cap at reasonable size
        
        tolerance = solver.get_double("convergence_tol", 1e-6)
        max_iterations = solver.get_int("max_iterations", 1000)
        restart = solver.get_int("restart", 50)
        verbose = system.get_bool("use_debug", False)
        
        console.print(f"🔧 [cyan]Converting XML config to GCR-Julia parameters[/cyan]")
        console.print(f"   📄 Config file: {config_file}")
        console.print(f"   🧮 Algorithm: {algorithm}")
        console.print(f"   ⚡ Backend: {backend}")
        console.print(f"   📊 Problem size: {problem_size} (from resolution {resolution})")
        
        # Call the solve command with converted parameters
        from click.testing import CliRunner
        runner = CliRunner()
        
        # Build command arguments
        args = [
            str(problem_size),
            '--algorithm', algorithm,
            '--backend', backend,
            '--tolerance', str(tolerance),
            '--max-iter', str(max_iterations),
            '--restart', str(restart)
        ]
        
        if verbose:
            args.append('--verbose')
        
        # Invoke the solve command
        result = runner.invoke(solve, args)
        
        if result.exit_code != 0:
            console.print(f"❌ [red]GCR-Julia execution failed[/red]")
            sys.exit(1)
        
    except Exception as e:
        console.print(f"❌ [red]Failed to process XML configuration: {e}[/red]")
        sys.exit(1)


# ==============================================================================
# UTILITY FUNCTIONS
# ==============================================================================

def _get_config_info(config_file: str) -> Dict[str, Any]:
    """Extract key information from configuration file."""
    parser = XMLConfigParser()
    if not parser.load_from_file(config_file):
        raise ValueError(f"Cannot parse configuration: {config_file}")
    
    config = parser.parse()
    
    # Extract information
    system = config.get_sublist("System")
    mpi = config.get_sublist("MPI")
    problem = config.get_sublist("Problem")
    solver = config.get_sublist("Solver")
    
    # Get description from root name
    description = config.name.replace('_', ' ') if config.name else "Configuration"
    
    return {
        'description': description,
        'solver': solver.get_string("type", "gcr"),
        'gpu': system.get_string("gpu_backend", "none"),
        'debug': system.get_bool("use_debug", False),
        'processes': mpi.get_int("total_processes", 4),
        'resolution': problem.get_double("resolution", 1.0),
        'maxit': solver.get_int("max_iterations", 20),
        'communication': system.get_string("communication", "mpi"),
    }


# ==============================================================================
# HELP AND INFO
# ==============================================================================

@cli.command()
def examples():
    """💡 Show common usage examples."""
    console.print("""
[bold cyan]🚀 GSM Quick Start Examples[/bold cyan]

[bold]1. Create and run a debug test:[/bold]
   gsm create --solver=gmres --gpu=cuda --debug config/my_debug.xml
   gsm run config/my_debug.xml

[bold]2. Use a template:[/bold]
   gsm template debug-cuda-gmres config/quick_test.xml
   gsm run config/quick_test.xml

[bold]3. Run with parameter overrides:[/bold]
   gsm run config/base.xml -o Solver.max_iterations=50 -o Problem.resolution=0.5

[bold]4. Validate configuration:[/bold]
   gsm validate config/my_config.xml

[bold]5. View configuration details:[/bold]
   gsm info config/my_config.xml
   gsm show config/my_config.xml

[bold]6. List all available configurations:[/bold]
   gsm list

[bold]7. Run GCR-Julia solvers:[/bold]
   gsm julia status                              - Check Julia environment
   gsm julia solve 1000 --algorithm=gcr         - Solve 1000x1000 system with GCR
   gsm julia solve 5000 --algorithm=ca-gcr --backend=gpu-cuda --verbose
   gsm julia run-config config/test.xml         - Run Julia solver with XML config

[bold cyan]📁 Standard Configuration Locations:[/bold cyan]
   config/debug_cuda_gmres.xml      - Debug CUDA GMRES
   config/production_ca_gcr.xml     - Production CA-GCR
   config/gcr_solver_config.xml     - Default template

[bold cyan]🔬 GCR-Julia Integration:[/bold cyan]
   • Pure Julia implementation with high performance
   • GPU acceleration via CUDA.jl and AMDGPU.jl
   • Multiple solver algorithms: GCR, CA-GCR, GMRES, BCA-GMRES
   • Seamless integration with GSM XML configurations

[bold cyan]🔄 Migration from Old GSM:[/bold cyan]
   Old: gsm run --solver=gmres --gpu=cuda --debug --nproc=2
   New: gsm create --solver=gmres --gpu=cuda --debug --nproc=2 config/test.xml
        gsm run config/test.xml
        
   Julia: gsm julia solve 2000 --algorithm=gmres --backend=gpu-cuda --verbose
""")


if __name__ == "__main__":
    cli()